﻿bool isOver = false;
int fps = 60;
long currentTime, lastTime;
ConsoleKeyInfo key;
Pos pos;
Dir dir;
string fileName = "../../../map.csv";
string fileName1 = "../../../TONGGUAN.csv";
string fileName2 = "../../../map2.csv";
int[,] map;
int[,] tongguan;
int[,] map2;
int boxCount;
Scene scene;
Menu selectMenue;
MenuCtrl menuCtrl;
Random scenerandom = new Random();
int a;
//Pos[] back;

#region 输入
// 输入
void Input()
{
    key = Console.ReadKey(true);  // 参数控制是否显示字符
    switch (scene)
    {
        case Scene.Menu:
            switch (key.Key)
            {
                case ConsoleKey.W:
                    menuCtrl = MenuCtrl.Up;
                    break;
                case ConsoleKey.S:
                    menuCtrl = MenuCtrl.Down;
                    break;
                case ConsoleKey.Enter:
                    menuCtrl = MenuCtrl.Select;
                    break;
            }
            break;
        case Scene.Scene1:
            switch (key.Key)
            {
                case ConsoleKey.UpArrow:
                case ConsoleKey.W:
                    dir = Dir.Up;
                    break;
                case ConsoleKey.DownArrow:
                case ConsoleKey.S:
                    dir = Dir.Down;
                    break;
                case ConsoleKey.LeftArrow:
                case ConsoleKey.A:
                    dir = Dir.Left;
                    break;
                case ConsoleKey.RightArrow:
                case ConsoleKey.D:
                    dir = Dir.Right;
                    break;
                case ConsoleKey.Q:
                    Init();
                    break;
                default:
                    break;
            }
            break;
        case Scene.Scene2:
            switch (key.Key)
            {
                case ConsoleKey.UpArrow:
                case ConsoleKey.W:
                    dir = Dir.Up;
                    break;
                case ConsoleKey.DownArrow:
                case ConsoleKey.S:
                    dir = Dir.Down;
                    break;
                case ConsoleKey.LeftArrow:
                case ConsoleKey.A:
                    dir = Dir.Left;
                    break;
                case ConsoleKey.RightArrow:
                case ConsoleKey.D:
                    dir = Dir.Right;
                    break;
                case ConsoleKey.Q:
                    Init();
                    break;
                default:
                    break;
            }
            break;
        case Scene.Scene3:
            break;
        default:
            break;
    }
    // 检测按键
    // 只更改状态 不做逻辑处理

}
#endregion

#region 画地图
void DrawMap(int[,] data)
{
    for (int i = 0; i < data.GetLength(0); i++)
    {
        for (int j = 0; j < data.GetLength(1); j++)
        {
            Console.SetCursorPosition(j, i);
            switch (data[i, j])
            {
                case (int)MapType.None:
                    Console.WriteLine(" ");
                    break;
                case (int)MapType.Wall:
                    Console.ForegroundColor = ConsoleColor.DarkMagenta;
                    Console.Write("N");
                    break;
                case (int)MapType.Box:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.Write("#");
                    break;
                case (int)MapType.Exit:
                    Console.ForegroundColor = ConsoleColor.DarkRed;
                    Console.Write("O");
                    break;
                case (int)MapType.Complete:
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.Write("@");
                    break;
                default:
                    break;
            }
        }
    }
}
void DrawMap1(int[,] data)
{
    for (int i = 0; i < data.GetLength(0); i++)
    {
        for (int j = 0; j < data.GetLength(1); j++)
        {
            Console.SetCursorPosition(j+38, i+6);
            switch (data[i, j])
            {
                case -1:
                    Console.WriteLine(" ");
                    break;
                case 0:
                    Console.ForegroundColor = ConsoleColor.DarkMagenta;
                    Console.Write("N");
                    break;
                default:
                    break;
            }
        }
    }
}


#endregion

#region 移动
void Move()
{
    //回退
    //for (int i = back.Length; i > 0; i--)
    //{
    //    back[i] = back[i - 1];
    //}
    // 根据移动方向修改坐标
    switch (dir)
    {
        case Dir.Up:
            pos.y--;
            //back[0].y--;
            break;
        case Dir.Down:
            pos.y++;
            //back[0].y++;
            break;
        case Dir.Left:
            pos.x--;
            //back[0].x--;
            break;
        case Dir.Right:
            pos.x++;
            //back[0].x++;
            break;
    }
}
#endregion

#region 推
void Push(MapType nextType, MapType originType)
{
    ChangeMapType(GetNextPos(), (int)nextType);
    ChangeMapType(pos, (int)originType);

    isOver = CheckOver();
}
void Push2(MapType nextType, MapType originType)
{
    ChangeMapType2(GetNextPos(), (int)nextType);
    ChangeMapType2(pos, (int)originType);

    isOver = CheckOver2();
}

#endregion

// 获取下一格坐标
Pos GetNextPos()
{
    Pos next;
    next.x = next.y = 0;
    next.x0 = next.y0 = 0;
    switch (dir)
    {
        case Dir.Up:
            next.x = pos.x;
            next.y = pos.y - 1;
            break;
        case Dir.Down:
            next.x = pos.x;
            next.y = pos.y + 1;
            break;
        case Dir.Left:
            next.x = pos.x - 1;
            next.y = pos.y;
            break;
        case Dir.Right:
            next.x = pos.x + 1;
            next.y = pos.y;
            break;
    }
    return next;
}

// 获取下下一格坐标
Pos GetNextNextPos()
{
    Pos next;
    next.x = next.y = 0;
    next.x0 = next.y0 = 0;
    switch (dir)
    {
        case Dir.Up:
            next.x = pos.x;
            next.y = pos.y - 2;
            break;
        case Dir.Down:
            next.x = pos.x;
            next.y = pos.y + 2;
            break;
        case Dir.Left:
            next.x = pos.x - 2;
            next.y = pos.y;
            break;
        case Dir.Right:
            next.x = pos.x + 2;
            next.y = pos.y;
            break;
    }
    return next;
}

// 根据坐标获得地图数据
int GetMapType(Pos pos)
{
    return map[pos.y, pos.x];
    
}
int GetMapType2(Pos pos)
{
    return map2[pos.y, pos.x];

}

// 修改地图数据
void ChangeMapType(Pos pos, int type)
{
    map[pos.y, pos.x] = type;
}
void ChangeMapType2(Pos pos, int type)
{
    map2[pos.y, pos.x] = type;
}

#region 初始化
void Init()
{
    // 初始化窗口
    Console.CursorVisible = false;
    Console.Title = "GameLoop";
    Console.SetWindowSize(100, 30);

    // 绘制边框
    Console.Clear();

    // 初始化数据
    map = new int[30, 60];
    tongguan = new int[20, 30];
    map2 = new int[30, 60];
    boxCount = 0;
    scene = Scene.Menu;
    selectMenue = Menu.Start;
    menuCtrl = MenuCtrl.None;

    //back = new Pos[10];

    /*back[0].x = */pos.x = 10;
    /*back[0].y = */pos.y = 10;
    // 读取文件
    if (File.Exists(fileName))
    {
        // 读取文件, 这里using表示只在这里读取(使用？)，出了之后释放？以免内存泄漏
        using (StreamReader sr = new StreamReader(fileName))
        {
            string data = sr.ReadToEnd();
            // 字符串分割 Split, 这里的文本中用",""换行"分离
            string[] lines = data.Split('\n'); // 分隔的也可使字符串
            for (int i = 0; i < lines.Length; i++)
            {
                string[] elements = lines[i].Split(',');
                for (int j = 0; j < elements.Length; j++)
                {
                    map[i, j] = int.Parse(elements[j]);
                    if (map[i, j] == (int)MapType.Box)
                    {
                        boxCount++;
                    }
                    if (map[i, j] == (int)MapType.Spawn)
                    {
                        map[i, j] = (int)MapType.None;
                        pos.x = j;
                        pos.y = i;
                    }
                }
            }
        };
    }
    if (File.Exists(fileName1))
    {
        // 读取文件, 这里using表示只在这里读取(使用？)，出了之后释放？以免内存泄漏
        using (StreamReader sr = new StreamReader(fileName1))
        {
            string data = sr.ReadToEnd();
            // 字符串分割 Split, 这里的文本中用",""换行"分离
            string[] lines = data.Split('\n'); // 分隔的也可使字符串
            for (int i = 0; i < lines.Length; i++)
            {
                string[] elements = lines[i].Split(',');
                for (int j = 0; j < elements.Length; j++)
                {
                    tongguan[i, j] = int.Parse(elements[j]);
                }
            }
        };
    }
    if (File.Exists(fileName2))
    {
        // 读取文件, 这里using表示只在这里读取(使用？)，出了之后释放？以免内存泄漏
        using (StreamReader sr = new StreamReader(fileName2))
        {
            string data = sr.ReadToEnd();
            // 字符串分割 Split, 这里的文本中用",""换行"分离
            string[] lines = data.Split('\n'); // 分隔的也可使字符串
            for (int i = 0; i < lines.Length; i++)
            {
                string[] elements = lines[i].Split(',');
                for (int j = 0; j < elements.Length; j++)
                {
                    map2[i, j] = int.Parse(elements[j]);
                    if (map2[i, j] == (int)MapType.Box)
                    {
                        boxCount++;
                    }
                    if (map2[i, j] == (int)MapType.Spawn)
                    {
                        map2[i, j] = (int)MapType.None;
                        pos.x = j;
                        pos.y = i;
                    }
                }
            }
        };
    }

    pos.x0 = pos.x;
    pos.y0 = pos.y;
    dir = Dir.None;
    
}
#endregion

#region 更新
void Update()
{
    Input();
    
    switch (scene)
    {
        case Scene.Menu:
            switch (menuCtrl)
            {
                case MenuCtrl.Up:
                    selectMenue--;
                    if (selectMenue < Menu.Start)
                    {
                        selectMenue = Menu.Exit;
                    }
                    break;
                case MenuCtrl.Down:
                    selectMenue++;
                    if (selectMenue > Menu.Exit)
                    {
                        selectMenue = Menu.Start;
                    }
                    break;
                case MenuCtrl.Select:
                    switch (selectMenue)
                    {
                        case Menu.Start:
                            a = scenerandom.Next(1, 3);
                            scene = (Scene)a;
                            Console.Clear();
                            break;
                        case Menu.Continue:
                            //读档
                            break;
                        case Menu.Exit:
                            Environment.Exit(0);
                            break;
                    }
                    break;
            }
            break;
        case Scene.Scene1:
            if (GetMapType(GetNextPos()) == (int)MapType.None
                || GetMapType(GetNextPos()) == (int)MapType.Exit)
            {
                Move();
            }
            else if (GetMapType(GetNextPos()) == (int)MapType.Box)
            {
                if (GetMapType(GetNextNextPos()) == (int)MapType.None)
                {
                    Move();
                    Push(MapType.Box, MapType.None);
                }
                else if (GetMapType(GetNextNextPos()) == (int)MapType.Exit)
                {
                    Move();
                    Push(MapType.Complete, MapType.None);
                    //boxCount--;
                    //isOver = boxCount == 0;
                }
            }
            else if (GetMapType(GetNextPos()) == (int)MapType.Complete)
            {
                if (GetMapType(GetNextNextPos()) == (int)MapType.None)
                {
                    Move();
                    Push(MapType.Box, MapType.Exit);
                    //boxCount++;
                }
                else if (GetMapType(GetNextNextPos()) == (int)MapType.Exit)
                {
                    Move();
                    Push(MapType.Complete, MapType.Exit);
                }
            }
            break;
        case Scene.Scene2:
            if (GetMapType2(GetNextPos()) == (int)MapType.None
                || GetMapType2(GetNextPos()) == (int)MapType.Exit)
            {
                Move();
            }
            else if (GetMapType2(GetNextPos()) == (int)MapType.Box)
            {
                if (GetMapType2(GetNextNextPos()) == (int)MapType.None)
                {
                    Move();
                    Push2(MapType.Box, MapType.None);
                }
                else if (GetMapType2(GetNextNextPos()) == (int)MapType.Exit)
                {
                    Move();
                    Push2(MapType.Complete, MapType.None);
                    //boxCount--;
                    //isOver = boxCount == 0;
                }
            }
            else if (GetMapType2(GetNextPos()) == (int)MapType.Complete)
            {
                if (GetMapType2(GetNextNextPos()) == (int)MapType.None)
                {
                    Move();
                    Push2(MapType.Box, MapType.Exit);
                    //boxCount++;
                }
                else if (GetMapType2(GetNextNextPos()) == (int)MapType.Exit)
                {
                    Move();
                    Push2(MapType.Complete, MapType.Exit);
                }
            }
            break;
        case Scene.Scene3:
            break;
        default:
            break;
    }
}
#endregion

#region 渲染
void Render()
{
    switch (scene)
    {
        case Scene.Menu:
            Print("推箱子", 41, 6, ConsoleColor.DarkYellow);
            Print("开始游戏", 40, 14, selectMenue == Menu.Start ? ConsoleColor.Red : ConsoleColor.White);
            Print("继续游戏", 40, 16, selectMenue == Menu.Continue ? ConsoleColor.Red : ConsoleColor.White);
            Print("结束游戏", 40, 18, selectMenue == Menu.Exit ? ConsoleColor.Red : ConsoleColor.White);
            break;
        case Scene.Scene1:
            DrawMap(map);
            // 画面
            Console.SetCursorPosition(pos.x0, pos.y0);
            Console.Write(" ");
            pos.y0 = pos.y;
            pos.x0 = pos.x;
            Console.SetCursorPosition(pos.x, pos.y); 
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.Write(GetMapType(pos) == (int)MapType.Exit ? "§" : "$");
            //信息
            Console.SetCursorPosition(70,5);
            Console.Write("W      ↑");
            Console.SetCursorPosition(62,6);
            Console.Write("移动: A S D  ← ↓ →");
            Console.SetCursorPosition(62, 8);
            Console.Write("返回主菜单:  Q");
            break;
        case Scene.Scene2:
            DrawMap(map2);
            // 画面
            Console.SetCursorPosition(pos.x0, pos.y0);
            Console.Write(" ");
            pos.y0 = pos.y;
            pos.x0 = pos.x;
            Console.SetCursorPosition(pos.x, pos.y);
            Console.ForegroundColor = ConsoleColor.Blue;
            Console.Write(GetMapType2(pos) == (int)MapType.Exit ? "§" : "$");
            //信息
            Console.SetCursorPosition(70, 5);
            Console.Write("W      ↑");
            Console.SetCursorPosition(62, 6);
            Console.Write("移动: A S D  ← ↓ →");
            Console.SetCursorPosition(62, 8);
            Console.Write("返回主菜单:  Q");
            break;
        case Scene.Scene3:
            break;
    }

}
#endregion

// 检测结束
bool CheckOver()
{
    int count = 0;
    for (int i = 0; i < map.GetLength(0); i++)
    {
        for (int j = 0; j < map.GetLength(1); j++)
        {
            if (map[i, j] == (int)MapType.Exit)
            {
                count++;
            }
        }
    }
    return count == 0;
}
bool CheckOver2()
{
    int count = 0;
    for (int i = 0; i < map2.GetLength(0); i++)
    {
        for (int j = 0; j < map2.GetLength(1); j++)
        {
            if (map2[i, j] == (int)MapType.Exit)
            {
                count++;
            }
        }
    }
    return count == 0;
}


#region 结束
void End()
{
    Console.Clear();
    //Console.SetCursorPosition(60, 15);
    //Console.WriteLine("通关");
    DrawMap1(tongguan);
    Thread.Sleep(100000);
}
#endregion

void Print(string str, int x, int y, ConsoleColor color = ConsoleColor.White)
{
    Console.SetCursorPosition(x, y);
    Console.ForegroundColor = color;
    Console.WriteLine(str);
    Console.ResetColor();
}

void Game()
{
    Init(); 
    lastTime = DateTime.Now.Ticks;
    while (!isOver)
    {
        Update(); 

        currentTime = DateTime.Now.Ticks;
        if (currentTime - lastTime > 10_000_000 / fps)
        {
            Render(); 
            lastTime = DateTime.Now.Ticks;
        }
    }
    End();
}

// 运行游戏
Game();

struct Pos
{
    public int x;
    public int y;
    public int x0;
    public int y0;
};

enum Dir
{
    None,
    Up,
    Down,
    Left,
    Right,
};

enum MapType
{
    None = 1,
    Wall = 0,
    Box = 2,
    Exit = 3,
    Complete,
    Spawn = 6
};

enum Scene
{
    Menu,
    Scene1,
    Scene2,
    Scene3,
}

enum Menu
{
    Start,
    Continue,
    Exit
}

enum MenuCtrl
{
    None,
    Up,
    Down,
    Select
}